package com.starlink.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.hutool.core.convert.Convert;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.lop.open.api.sdk.domain.ECAP.CommonCreateOrderApi.commonCreateOrderV1.CommonCreateOrderResponse;
import com.lop.open.api.sdk.domain.ECAP.CommonSubscribeTraceApi.commonSubscribeTraceV1.Response;
import com.lop.open.api.sdk.domain.jdcloudprint.PullDataService.pullData.PrePrintDataInfo;
import com.starlink.client.jd.JdClient;
import com.starlink.client.jd.properties.JdProperties;
import com.starlink.client.jd.request.PullDataRequest;
import com.starlink.client.jd.request.SubscribeTraceRequest;
import com.starlink.client.jd.request.base.WayBillInfoRequest;
import com.starlink.client.jd.vo.PrintContentsVO;
import com.starlink.client.jd.vo.PrintPullDataVO;
import com.starlink.common.annotation.client.WeixinJsClient;
import com.starlink.common.annotation.client.base.RefundAmount;
import com.starlink.common.annotation.client.weixin.UserPurchaseRes;
import com.starlink.common.annotation.client.weixin.WeixinJsRefundOrderReq;
import com.starlink.common.annotation.client.weixin.WeixinJsRefundOrderRes;
import com.starlink.common.enums.LogisticsOrderBusinessEnum;
import com.starlink.common.enums.OrderTypeEnum;
import com.starlink.common.enums.StarSecondTypeEnum;
import com.starlink.common.enums.StarTypeEnum;
import com.starlink.common.service.JdService;
import com.starlink.common.strategy.IStarOrder;
import com.starlink.context.SessionContext;
import com.starlink.mapper.AdminAddressMapper;
import com.starlink.model.domain.*;
import com.starlink.model.request.*;
import com.starlink.model.request.mall.WechatRefund;
import com.starlink.model.request.other.StarOrderRefundRequest;
import com.starlink.model.request.other.StarOrderSubmitRequest;
import com.starlink.model.util.AddressConvert;
import com.starlink.model.util.AdminAddressConvert;
import com.starlink.model.util.AdminConvert;
import com.starlink.model.vo.*;
import com.starlink.model.vo.manual.WriteOffRecord;
import com.starlink.service.*;
import com.starlink.utils.IRedisCacheService;
import com.starlink.utils.MoneyUtil;
import com.starlink.utils.OrderNumUtil;
import org.springframework.data.domain.Pageable;
import com.starlink.common.utils.AssertUtil;
import com.starlink.model.dtomapper.OtherOrderDtoMapper;
import com.starlink.mapper.OtherOrderMapper;
import com.starlink.model.util.OtherOrderConvert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.starlink.common.enums.FreeEnum.FA_HUO_SHIPING;
import static com.starlink.common.enums.RedisHashKeyEnum.ORDER_REFUND;
import static com.starlink.utils.PageUtils.getOrderBy;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author zhanghong
 */
@Service
public class OtherOrderServiceImpl extends ServiceImpl<OtherOrderMapper, OtherOrderDO> implements OtherOrderService {
    @Autowired
    private OtherOrderMapper otherOrderMapper;
    @Autowired
    private AddressService addressService;
    @Autowired
    private List<IStarOrder> starOrderPays;
    @Autowired
    private UserService userService;
    @Autowired
    private WeixinJsClient weixinJsClient;
    @Autowired
    private IRedisCacheService redisCacheService;
    @Autowired
    private MallLogisticsService logisticsService;
    @Autowired
    private JdClient jdClient;
    @Autowired
    private JdProperties jdProperties;
    @Autowired
    private JdService jdService;
    @Autowired
    private AdminAddressMapper adminAddressMapper;

    private static final long EXPIRE_SECONDS = 7 * 24 * 60 * 60; // 过期时间，单位：秒

    @Override
    public OtherOrderVO getByKey(long id) {
        OtherOrderDO byId = getById(id);
        OtherOrderVO otherOrderVO = OtherOrderDtoMapper.INSTANCE.do2VO(byId);
        assembly(otherOrderVO);
        return otherOrderVO;
    }

    private void assembly(OtherOrderVO otherOrderVO) {
        StarTypeEnum starTypeEnum = StarTypeEnum.getByType(otherOrderVO.getStarType());
        for (IStarOrder starOrderPay : starOrderPays) {
            if (starOrderPay.supports(starTypeEnum)) {
                otherOrderVO.setBizObj(starOrderPay.getBizInfo(otherOrderVO.getBizId()));
            }
        }
        // 查询下单用户信息
        UserVO userVO = userService.getByKey(otherOrderVO.getUserId());
        if (userVO != null) {
            otherOrderVO.setUserName(Optional.ofNullable(userVO.getRealName()).orElse(userVO.getNickName()));
            otherOrderVO.setMobile(userVO.getMobile());
        }

        // 翻译核销记录
        List<WriteOffRecord> writeOffRecords = Optional.ofNullable(otherOrderVO.getExtInfo()).map(item -> JSON.parseArray(item, WriteOffRecord.class)).orElse(Lists.newArrayList());
        otherOrderVO.setWriteOffRecordList(writeOffRecords);
    }

    @Override
    public PageInfo<OtherOrderVO> pageQuery(Pageable pageable, OtherOrderRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize(), getOrderBy(pageable.getSort())).setReasonable(true);
        List<OtherOrderDO> list = otherOrderMapper.listQuery(request);
        List<OtherOrderVO> otherOrderVOList = OtherOrderConvert.buildOtherOrderVoList(list);
        otherOrderVOList.forEach(item -> assembly(item));
        return new PageInfo(otherOrderVOList);
    }

    @Override
    public List<OtherOrderVO> listQuery(OtherOrderRequest request) {
        List<OtherOrderDO> list = otherOrderMapper.selectDOList(OtherOrderDtoMapper.INSTANCE.request2DO(request));
        List<OtherOrderVO> otherOrderVOList = OtherOrderConvert.buildOtherOrderVoList(list);
        otherOrderVOList.forEach(item -> assembly(item));
        return otherOrderVOList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(OtherOrderRequest request) {
        save(OtherOrderDtoMapper.INSTANCE.request2DO(request));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByKey(OtherOrderRequest request) {
        AssertUtil.assertNotNull(request.getId(), "id不能为空");
        saveOrUpdate(OtherOrderDtoMapper.INSTANCE.request2DO(request));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteDOByIds(String ids) {
        otherOrderMapper.deleteDOByIds(Convert.toStrArray(ids));
        return true;
    }

    @Override
    public UserPurchaseRes payment(StarOrderSubmitRequest request) {
        AssertUtil.assertNotNull(request.getStarId(), "商品id不能为空");
        AssertUtil.assertNotNull(request.getBuyNum(), "商品购买数量不能为空");
        AssertUtil.assertTrue(request.getBuyNum() > 0, "商品购买数量至少为1");
        AssertUtil.assertNotNull(request.getStarType(), "商品类型不能为空!");
        StarTypeEnum starTypeEnum = StarTypeEnum.getByType(request.getStarType());
        AssertUtil.assertNotNull(starTypeEnum, "商品类型非法!");
        AssertUtil.assertNotNull(request.getAddressId(), "请选择收获地址!");
        AssertUtil.assertNotNull(addressService.getByKey(request.getAddressId()), "收获地址不存在!");

        UserPurchaseRes vipRes = null;
        try {
            for (IStarOrder starOrderPay : starOrderPays) {
                if (starOrderPay.supports(starTypeEnum)) {
                    vipRes = starOrderPay.prePayment(request);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("微信下单失败!");
        }
        return vipRes;
    }

    @Override
    public Boolean writeOff(OtherOrderRequest request) {
        AssertUtil.assertNotNull(request.getId(), "id不能为空");
        OtherOrderDO byId = getById(request.getId());
        AssertUtil.assertNotNull(byId, "订单不存在");
        Long serviceNum = Optional.ofNullable(byId.getServiceNum()).orElse(0L);
        serviceNum = serviceNum + request.getWriteOffNum();
        AssertUtil.assertTrue(serviceNum <= byId.getPurchaseNum(), "核销总次数超过购买次数总额");
        byId.setServiceNum(serviceNum);
        List<WriteOffRecord> writeOffRecords = Optional.ofNullable(byId.getExtInfo()).map(item -> JSON.parseArray(item, WriteOffRecord.class)).orElse(Lists.newArrayList());
        WriteOffRecord record = new WriteOffRecord();
        record.setWriteOffNum(request.getWriteOffNum());
        record.setWriteOffTime(new Date());
        record.setWriteOffImg(request.getWriteOffImg());
        writeOffRecords.add(record);
        byId.setExtInfo(JSON.toJSONString(writeOffRecords));
        saveOrUpdate(byId);
        return true;
    }

    @Override
    public Boolean refund(StarOrderRefundRequest request) {
        AssertUtil.assertNotNull(request.getOrderId(), "订单id不能为空");
        OtherOrderDO otherOrderDO = otherOrderMapper.selectDOById(request.getOrderId());
        AssertUtil.assertNotNull(otherOrderDO, "订单不存在");
        AssertUtil.assertTrue(NumberUtil.compare(otherOrderDO.getOrderMoney().doubleValue(), request.getRefundMoney().doubleValue()) >= 0, "退款金额大于订单金额");
        if (otherOrderDO.getStarType() == 1 && otherOrderDO.getStarSecondType() == 1) {
            // 智能穿戴仅支持发货时用户端发起退款
            AssertUtil.assertTrue(otherOrderDO.getDeliveryStatus() == 1, "订单状态异常");
        }

        otherOrderDO.setRefundOrderNo(OrderNumUtil.createUniqueOrderNum());
        try {
            //退款金额
            RefundAmount refundAmount = new RefundAmount();
            refundAmount.setRefund(MoneyUtil.yuan2fen(0.01d));
            refundAmount.setTotal(MoneyUtil.yuan2fen(0.01d));

            StarTypeEnum starTypeEnum = StarTypeEnum.getByType(otherOrderDO.getStarType());
            StarSecondTypeEnum secondaryTypeEnum = StarSecondTypeEnum.getByType(otherOrderDO.getStarSecondType());

            WeixinJsRefundOrderReq req = WeixinJsRefundOrderReq.starRefundOrderReq(otherOrderDO, refundAmount,
                    null, String.format("%s：%s订单退款", starTypeEnum.getDesc(), secondaryTypeEnum.getDesc()));
            WeixinJsRefundOrderRes refundRes = weixinJsClient.createRefundOrder(req);
            otherOrderDO.setOrderStatus(4);
            otherOrderDO.setWxRefundOrderNo(refundRes.getRefund_id());
            otherOrderDO.setRefundMoney(request.getRefundMoney());
            saveOrUpdate(otherOrderDO);

            WechatRefund wechatRefund = new WechatRefund();
            wechatRefund.setOrderId(otherOrderDO.getId());
            wechatRefund.setRefundNum(otherOrderDO.getOrderNo());
            wechatRefund.setOrderType(OrderTypeEnum.STAR.getType());
            redisCacheService.hashPushHashMap(ORDER_REFUND.name(), otherOrderDO.getRefundOrderNo(),
                    wechatRefund, EXPIRE_SECONDS, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("微信退款失败!");
        }
        return true;
    }

    @Override
    public Boolean deliverySubmitJdOrder(OtherOrderRequest request) {
        // 前置校验
        AssertUtil.assertNotNull(request.getId(), "订单id不能为空");
        OtherOrderDO order = otherOrderMapper.selectDOById(request.getId());
        AssertUtil.assertNotNull(order, "订单不存在");

        //物流下单
        String logisticsOrderNum = LogisticsOrderBusinessEnum.SMART_WEARABLE.getCode() + OrderNumUtil.createJdUniqueOrderNum();
        CommonCreateOrderResponse response = jdService.creatJDOrder(1,
                "星健康",
                AdminAddressConvert.buildContact(adminAddressMapper.selectOne()),
                AddressConvert.buildContact(addressService.lambdaQuery().eq(AddressDO::getId, order.getAddressId()).one()),
                new AtomicReference(new BigDecimal("0.1")),
                new AtomicReference(new BigDecimal("0.1")),
                logisticsOrderNum);

        //新增商家物流信息
        MallLogisticsRequest logisticsRequest = new MallLogisticsRequest();
        logisticsRequest.setOrderId(order.getId());
        logisticsRequest.setSubOrderId(order.getId());
        logisticsRequest.setLogisticsNum(logisticsOrderNum);
        logisticsRequest.setAddressId(order.getAddressId());
        logisticsRequest.setOrderType(6);
        logisticsRequest.setShippingDate(new Date());
        logisticsRequest.setShippingMethod("JD");
        logisticsRequest.setFreeType(FA_HUO_SHIPING.getType());
        logisticsRequest.setCreateTime(new Date());
        logisticsRequest.setCreateUser(SessionContext.getAdminUserId());
        logisticsRequest.setLogisticsOrderId(response.getOrderCode());
        logisticsRequest.setWaybillCode(response.getWaybillCode());
        logisticsRequest.setFreight(response.getFreightPre());
        logisticsService.add(logisticsRequest);

        // 更新数据
        order.setWaybillCode(response.getWaybillCode());
        order.setDeliveryTime(new Date());
        order.setOrderStatus(2);
        order.setDeliveryStatus(2);
        saveOrUpdate(order);
        return true;
    }

    @Override
    public PrintPullDataVO getPrintData(OtherOrderRequest request) {
        AssertUtil.assertNotNull(request.getId(), "订单ID不能为空!");
        MallLogisticsDO logisticsDO = logisticsService.lambdaQuery()
                .eq(MallLogisticsDO::getOrderId, request.getId())
                .eq(MallLogisticsDO::getOrderType, 6)
                .eq(MallLogisticsDO::getFreeType, FA_HUO_SHIPING.getType())
                .last("limit 1")
                .one();
        AssertUtil.assertNotNull(logisticsDO, "物流订单不存在!");
        String waybillCode = logisticsDO.getWaybillCode();
        PullDataRequest pullDataRequest = new PullDataRequest();
        pullDataRequest.setObjectId(OrderNumUtil.createUniqueOrderNum());
        WayBillInfoRequest wayBillInfoRequest = new WayBillInfoRequest();
        wayBillInfoRequest.setJdWayBillCode(waybillCode);
        List<WayBillInfoRequest> wayBillInfoRequests = Arrays.asList(wayBillInfoRequest);
        pullDataRequest.setWayBillInfos(wayBillInfoRequests);
        List<PrePrintDataInfo> dataInfos = jdClient.pullData(pullDataRequest);
        PrintPullDataVO printPullDataVO = new PrintPullDataVO();
        List<PrintContentsVO> printData = new ArrayList<>();
        dataInfos.forEach(dataInfo -> {
            String perPrintData = dataInfo.getPerPrintData();
            PrintContentsVO printContentsVO = new PrintContentsVO(jdProperties.getTempUrl(), perPrintData);
            printData.add(printContentsVO);
        });
        PrintPullDataVO pullDataVO = printPullDataVO.toPrintPullDataVO(OrderNumUtil.createPrintNum(), printData);
        return pullDataVO;
    }

    @Override
    public Boolean confirm(OtherOrderRequest request) {
        AssertUtil.assertNotNull(request.getId(), "订单ID不能为空!");
        OtherOrderDO otherOrderDO = otherOrderMapper.selectDOById(request.getId());
        AssertUtil.assertNotNull(otherOrderDO, "订单不存在");
        AssertUtil.assertTrue(otherOrderDO.getDeliveryStatus() == 3, "订单状态异常");

        otherOrderDO.setDeliveryStatus(4);//收货
        saveOrUpdate(otherOrderDO);
        return true;
    }
}
